package com.zhangkang.stock.stocklib.tools

import com.zhangkang.stock.stocklib.data.RSI

/**
 * @author : Android-张康
 * created on: 2023/5/9 11:11
 * description:
 */
class RSITools(private val n1: Int, private val n2: Int, private val n3: Int) {

    /**
     * 计算RSI
     *
     * @param data 当前的数据
     * @param currentIndex 当前数据
     * @param previousRSI 上一个RSI
     * @param getUpOrDown 获取涨跌幅
     */
    fun <T> calculationRSI(
        data: List<T>,
        currentIndex: Int,
        getRSI: (T) -> Map<Int, RSI>,
        getUpOrDown: (T) -> Float,
    ): Map<Int, RSI> {
        val returnMap = mutableMapOf<Int, RSI>()
        var n1RSI = calculationRSI(n1, data, currentIndex, getRSI, getUpOrDown)
        if (null == n1RSI) {
            n1RSI = RSI(averageIncrease = 0F, averageDecline = 0F, rsi = 0F)
        }
        returnMap[n1] = n1RSI

        var n2RSI = calculationRSI(n2, data, currentIndex, getRSI, getUpOrDown)
        if (null == n2RSI) {
            n2RSI = RSI(averageIncrease = 0F, averageDecline = 0F, rsi = 0F)
        }
        returnMap[n2] = n2RSI
        var n3RSI = calculationRSI(n3, data, currentIndex, getRSI, getUpOrDown)
        if (null == n3RSI) {
            n3RSI = RSI(averageIncrease = 0F, averageDecline = 0F, rsi = 0F)
        }
        returnMap[n3] = n3RSI
        return returnMap
    }

    /**
     * 计算RSI
     *
     * @param data 当前的数据
     * @param currentIndex 当前数据
     * @param previousRSI 上一个RSI
     * @param getUpOrDown 获取涨跌幅
     */
    private fun <T> calculationRSI(
        n: Int,
        data: List<T>,
        currentIndex: Int,
        getRSI: (T) -> Map<Int, RSI>,
        getUpOrDown: (T) -> Float,
    ): RSI? {
        return if (currentIndex < n - 1) {
            null
        } else if (currentIndex == n - 1) {
            calculationFirstRSI(n, data, getUpOrDown)
        } else {
            calculationRSI(
                n,
                getRSI(data[currentIndex - 1])[n]!!,
                getUpOrDown(data[currentIndex])
            )
        }
    }

    /**
     * 第一个 RSI 计算公式
     * (1) 将前n个（含n）交易周期中收盘价上涨日的收盘价增幅求和，除n，得收盘价平均增幅；
     * (2) 将前n个（含n）交易周期中收盘价下跌日的收盘价减幅求和，除n，得收盘价平均减幅；
     * (3) RSI（首个）=收盘价平均增幅/（收盘平均增幅+收盘平均减幅）* 100 ；
     */
    private fun <T> calculationFirstRSI(n: Int, data: List<T>, getUpOrDown: (T) -> Float): RSI {
        //计算平均增幅
        var totalIncrease = 0F
        //计算平均跌幅
        var totalDecline = 0F
        for (index in n - 1 downTo 1) {
            val upOrDown = getUpOrDown(data[index])
            if (upOrDown >= 0) {
                totalIncrease += upOrDown
            } else {
                totalDecline += -upOrDown
            }
        }

        //计算平均增幅
        val averageIncrease = totalIncrease / n
        //计算平均跌幅
        val averageDecline = totalDecline / n
        val calculationRSI = calculationRSI(averageIncrease, averageDecline)
        return RSI(
            averageIncrease = averageIncrease,
            averageDecline = averageDecline,
            rsi = calculationRSI
        )
    }

    /**
     * RSI 计算公式
     * (1) 将前一个收盘价平均增幅乘（n-1），加上当日的收市价增幅，除n，得收盘价平均增幅（非首个）；
     * (2)将前一个收盘价平均减幅乘（n-1），加上当日的收市价减幅，除n，得收盘价平均减幅（非首个）；
     * (3) RSI（后续）=收盘价平均增幅/（收盘平均增幅+收盘平均减幅）* 100 ；
     */
    private fun calculationRSI(n: Int, previousRSI: RSI, upOrDown: Float): RSI {
        //计算平均增幅
        val averageIncrease: Float
        //计算平均跌幅
        val averageDecline: Float
        if (upOrDown >= 0) {
            averageIncrease = calculationAverage(n, previousRSI.averageIncrease, upOrDown)
            averageDecline = calculationAverage(n, previousRSI.averageDecline, 0F)
        } else {
            averageIncrease = calculationAverage(n, previousRSI.averageIncrease, 0F)
            averageDecline = calculationAverage(n, previousRSI.averageDecline, -upOrDown)
        }
        val calculationRSI = calculationRSI(averageIncrease, averageDecline)
        return RSI(
            averageIncrease = averageIncrease,
            averageDecline = averageDecline,
            rsi = calculationRSI
        )
    }

    /**
     * RSI 计算公式
     * (1) 将前一个收盘价平均增幅乘（n-1），加上当日的收市价增幅，除n，得收盘价平均增幅（非首个）；
     * (2)将前一个收盘价平均减幅乘（n-1），加上当日的收市价减幅，除n，得收盘价平均减幅（非首个）；
     * (3) RSI（后续）=收盘价平均增幅/（收盘平均增幅+收盘平均减幅）* 100 ；
     *
     * @param averageIncrease 平均增幅
     * @param averageDecline  平均减幅
     */
    private fun calculationRSI(averageIncrease: Float, averageDecline: Float): Float {
        return averageIncrease / (averageIncrease + averageDecline) * 100
    }

    /**
     * 计算平均值
     */
    private fun calculationAverage(n: Int, previousAverage: Float, upOrDown: Float): Float {
        return (previousAverage * (n - 1) + upOrDown) / n
    }


}